/******************************************************************************
*   Sprite Handler
*   This file contains all sprite OAM functionality and also the SpriteHandler
*   structure with it's functionality.
*   Contains: SpriteAttributes, SpriteHandler
*******************************************************************************/

/** How to use SpriteHandlers

// Create Sprite Handler
// this allocates the new sprite, sets it's ID, and then returns a pointer to it, in memory
SpriteHandler * player = newSpriteHandler( SpriteHandler info );

// Setting the Data of the Player SpriteHandler
player->x = 50;
player->y = 70;

// Performing complex tasks which use functions to change attributes of player spritehandler
spriteAddAnimation( player, ANIM_IDLE, idle_anim_info );

// Record the unique sprite ID for the player
int player_sprite_id = player->ID;

// ... later in code, where the player sprite_handler pointer is out of scope

// Using the player_sprite_id refers to the same player sprite_handler in memory
// Updating the Info of the SpriteHandler into our copy of the Sprite Attribute strucutre
updateSpriteAttributes( player_sprite_id );

// ...


// Drawing the Sprite ( copying our version of the sprite attributes into OAM )
CopySpritesIntoOAM();

// SpriteHandler * freeing is done by sprite handler system, DO NOT FREE YOUR POINTER OF THE SPRITE HANDLER
// NO
free( player );

// yes
freeSprites();

// BEST PRACTICE NOTE: 
//		* User data should be used for information specific to that character type
//		* Add an updateSpriteAttributes in each character's update function because the system
//			 doesn't do this during updateSpriteHandlers.  Do this if you change attributes of a 
//			 sprite handler during the update ( position, rotation, etc )
//		* Use animations for everything, even single frame animations. This makes switching
//			between other animations easier.
*/


#ifndef SPRITE_HANDLER_H
#define SPRITE_HANDLER_H

#include "globals.h"
//#include "data/sprite_frame_test_data.h"
//#include "characters.h"
#include "data/sprites16x16.h"
#include "data/sprites8x8.h"
#include "data/sprites32x32.h"
#include "data/spritePalette.h"

//#include "world_camera.h"

////////////////////////////////////////////////////////////
// defines
////////////////////////////////////////////////////////////

// Max number of sprites
#define MAX_SPRITES 128

#define MAX_SPRITE_HANDLERS 10

// This is the maximum number of frames a single animation can have
#define MAX_FRAMES 20

// Max Animations as SpriteHandler can contain
#define MAX_ANIMATIONS 10


////////////////////////////////////////////////////////////
// rotation defines
////////////////////////////////////////////////////////////
#define PI 3.14159265
#define RADIAN(n) (((float)n) / (float)180 * PI)


////////////////////////////////////////////////////////////
// enumumerations
////////////////////////////////////////////////////////////

// All Possible Sprite Dimensions
typedef enum
{
    SD_8x8 = 0,
    SD_8x16,
    SD_8x32,
    SD_16x8,
    SD_16x16,
    SD_16x32,
    SD_32x8,
    SD_32x16,
    SD_32x32,
    SD_32x64,
    SD_64x32,
    SD_64x64
} SpriteDimensions;

// All Flip Types a sprite can have
typedef enum 
{
    FLIP_NONE 	= 0x0000,
    FLIP_HORIZ 	= HORIZONTAL_FLIP,
    FLIP_VERT 	= VERTICAL_FLIP
} FlipType;

typedef enum
{
	CHAR_NONE = 0,
	CHAR_PLAYER,
	CHAR_HEALTH,
	CHAR_UPGARDE,
	CHAR_ENEMY1,
	CHAR_ENEMY2,
	CHAR_ENEMY_TURRENT,
	CHAR_LASER,
	CHAR_ENEMY_BOSS,
	CHAR_ENEMY,
	CHAR_EXPLOSION
} CharacterType;

typedef enum
{
    // 16x16 sprites take up 8 "spaces"
    FRAME_PLAYER_1 = 0,
    FRAME_PLAYER_2 = 8,
    FRAME_ENEMY_16x16_PURPLE_1 = 16,
    FRAME_ENEMY_16x16_PURPLE_2 = 24,
    FRAME_ENEMY_16x16_BLUE_1 = 32,
    FRAME_ENEMY_16x16_BLUE_2 = 40,
    FRAME_EXPLOSION_1 = 48,
    FRAME_EXPLOSION_2 = 56,
    FRAME_EXPLOSION_3 = 64,
    FRAME_EXPLOSION_4 = 72,
    FRAME_ASTEROID_16x16 = 80,
    
    // 8x8 sprites take up 2 "spaces"
    FRAME_LASER_LEVEL_1 = 88,
    FRAME_LASER_LEVEL_2 = 90,
    FRAME_LASER_LEVEL_3 = 92,
    FRAME_LASER_LEVEL_4 = 94,
    FRAME_TURRET_1 = 96,
    FRAME_TURRET_2 = 98,
    FRAME_ENEMY_8x8_1 = 100,
    FRAME_ENEMY_8x8_2 = 102,
    FRAME_POWERUP_1 = 104,
    FRAME_POWERUP_2 = 106,
    FRAME_HEALTH_PACK = 108,
    FRAME_ASTEROID_8x8 = 110,
    
    // 32x32 sprites take up 32 "spaces"
    FRAME_BOSS_1 = 112,
    FRAME_BOSS_2 = 144
} SpriteFrameIndex;

////////////////////////////////////////////////////////////
// enumumerations
////////////////////////////////////////////////////////////

//OAM
typedef struct STRUCT_SPRITE_ATTRIBUTES 
{
	unsigned short attribute0;
	unsigned short attribute1;
	unsigned short attribute2;
	signed short fill;
} SpriteAttributes;

// this struct points to the same address in OAM as the SpriteAttributes struct defined above
typedef struct tagRotData
{
    unsigned short fill0[3];
    signed short pa;
    unsigned short fill1[3];
    signed short pb;
    unsigned short fill2[3];
    signed short pc;
    unsigned short fill3[3];
    signed short pd;
} RotData,*pRotData;

// Contains information for a single animation.
typedef struct ANIM_INFO_STRUCT
{
    int updatesPerFrame;    // number of updates that need to pass before switching to next frame
    int numFrames;
    BOOL looping;
    FlipType flip;
    int frames [ MAX_FRAMES ];      // sprie indeces for each frame of the animation
} AnimationInfo;

// forward declaration
struct SPRITE_HANDLER_STRUCT;

// Update function pointer typedef
typedef void(*update_func_ptr)(struct SPRITE_HANDLER_STRUCT*);

// Sprite Handler structure
typedef struct SPRITE_HANDLER_STRUCT
{
	// Unique id for this sprite handler. 
	// this is the same index for this sprite in g_spriteAttributes
    int id;		
    
    signed char x, y;
    
    SpriteDimensions size;
    int width, height;
	
	BOOL alive;		// is the sprite currently used?
	// BOOL enabled;
    
    FlipType flip;      // NOT IMPLEMENTED
    
    int priority;       // NOT IMPLEMENTED

    int _imageIndex;    // image frame index of this sprite
    
    int currentAnimation;
    AnimationInfo animations[ MAX_ANIMATIONS ];   // array of animations
    int _currentFrame;  // current frame of the current animation 0 to numFrames;
    int _currentUpdate; // current update for the current animation
	BOOL animationComplete;

    //signed int canRotate;
    //signed int affineMatrixIndex;
    
    signed int scale;
    signed int angle;
	
	// User data. TODO: Teach Danny how to use, it is VERY useful, and once we get this sprite handler crap set in stone, 
	//		we will never have to look at this bloated file ever again
	void * userData;	// User Data pointer
	
	// Update function used by the sprite_handler
	// update_func_ptr updateFunction;
	CharacterType characterType;
	
} SpriteHandler;

////////////////////////////////////////////////////////////
// Global Varriables
////////////////////////////////////////////////////////////

// chunk of memory that matches OAM
SpriteAttributes g_spriteAttributes[ MAX_SPRITES ]; 

// points to the SpriteAttributes structs array defined above
pRotData rotData = (pRotData)g_spriteAttributes;

// All Sprite Handlers that we use
// Note: mapping of g_spriteAttributes and g_spriteHandlers should refer to same sprites
// g_spriteHandlers[ 2 ] == g_spriteAttributes[ 2 ];
SpriteHandler g_spriteHandlers[ MAX_SPRITE_HANDLERS ];

// precomputed sine and cosine arrays for sprite rotation
signed int SIN[360];
signed int COS[360];

////////////////////////////////////////////////////////////
// function prototypes
////////////////////////////////////////////////////////////

// Function prototype to updateCharacer, implement in characters.h
void updateCharacter( SpriteHandler * character );

// System wide functions
void initSpriteHandlerSystem(void);
void LoadContentForSprites(void);
void updateSpriteHandlers(void);
void CopySpritesIntoOAM(void);
void cleanAllSprites(void);

// Sprite Handler Creation
SpriteHandler * newSpriteHandler(void);

// Sprite Handler "Methods"
void updateSpriteAttributes( SpriteHandler const * );

void AddSpriteAnimation(SpriteHandler *, int const, AnimationInfo const);
void SetSpriteAnimation(SpriteHandler *, int);
void UpdateSpriteAnimation(SpriteHandler *);

int GetSpriteWidth(SpriteHandler const *);
int GetSpriteHeight(SpriteHandler const *);
int GetSpriteAffineMatrixIndex(SpriteHandler const *);

// INTERNALLY USED FUNCTIONS. DON'T USE outside of this file
int getNextSpriteHandlerID();
void cleanSpriteHandler( int const id );
void RotateSprite(int rotDataIndex, int angle, signed int xscale, signed int yscale);

////////////////////////////////////////////////////////////
// Function: initSpriteHandlerSystem
// Initializes the Sprite Handler system for the first time.
// Only needs to be run once, at the begining of the game
////////////////////////////////////////////////////////////
void initSpriteHandlerSystem()
{
    int n;
	
	for ( n = 0 ; n < MAX_SPRITE_HANDLERS ; ++n )
	{
		g_spriteHandlers[ n ].alive = FALSE;
		g_spriteHandlers[ n ].userData = NULL;
		//g_spriteHandlers[ n ].updateFunction = NULL;
	}
	// memset ( g_spriteHandlers, 0, sizeof(SpriteHandler) * MAX_SPRITES );
	//__toncset( g_spriteHandlers, 0, sizeof(SpriteHandler) * MAX_SPRITES );
    
	// Clean out all SpriteHandler entries
	memset ( g_spriteAttributes, 0, sizeof( SpriteAttributes ) * MAX_SPRITES );
	
	for ( n = 0 ; n < MAX_SPRITES ; ++n )
	{
		g_spriteAttributes[ n ].attribute0 = SCREEN_HEIGHT;
		g_spriteAttributes[ n ].attribute1 = SCREEN_WIDTH;		
	}
	
	// for rotation
    for (n = 0; n < 360; n++) {
        SIN[n] = (signed int)(sin(RADIAN(n)) * 256);
        COS[n] = (signed int)(cos(RADIAN(n)) * 256);
    }
	
	// initialize hardcoded sprite affine matrices in 15 degree increments
    for (n = 0; n < 32; n++) {
        if (n < 24) {
            RotateSprite(n, (n * 15), 1 << 8, 1 << 8);
        }
        else {
            RotateSprite(n, 0, 1 << 8, 1 << 8);
        }
    }
}


////////////////////////////////////////////////////////////
// Function: LoadContentForSprites
// one time stuff for scrolling background; copies content into proper memory locations
////////////////////////////////////////////////////////////
void LoadContentForSprites()
{
    int i, j;
	
    // load palette	
	DMAFastCopy((void*)spritePalette, (void*)SpritePal, 256, DMA_16NOW);
	
	// load image data for the 16x16px sprites
	DMAFastCopy((void*)sprites16x16Data, (void*)SpriteData, 1408, DMA_16NOW);
	
	// load image data for the 8x8px sprites	
	for (i = 1408, j = 0; i < 1792; i++, j++) {
	    SpriteData[i] = sprites8x8Data[j];
    }
    
   	// load image data for the 8x8px sprites	
	for (i = 1792, j = 0; i < 2816; i++, j++) {
	    SpriteData[i] = sprites32x32Data[j];
    }
}

////////////////////////////////////////////////////////////
// Function: cleanAllSprites
// Frees the memory and cleans out all Sprites.
// Useful for level switching
////////////////////////////////////////////////////////////
void cleanAllSprites()
{
	// Clean out all SpriteHandler entries
	int id;	
	for ( id = 0 ; id < MAX_SPRITE_HANDLERS ; ++id )
	{
		g_spriteHandlers[ id ].alive = FALSE;
		updateSpriteAttributes( &g_spriteHandlers[ id ] );
	}
}

////////////////////////////////////////////////////////////
// Function: updateSpriteHandlers
// Updates the logic of every sprite handler
////////////////////////////////////////////////////////////
void updateSpriteHandlers()
{
	int i = 0;
    
	// Foreach sprite handler
    for ( i = 0 ; i < MAX_SPRITE_HANDLERS ; ++i )
    {
		// get pointer to the spirte handler at this index
        SpriteHandler * sprite_handler = &g_spriteHandlers[ i ];		
        
		// If it's dead
		if ( sprite_handler->alive )	// if its alive
		{
			updateCharacter( sprite_handler );
		}
		// It it's dead, dont' do anything.  Deallocation is done when a new id is needed		
    } // foreach sprite handler
	
	// cull for invisible
	// cullForInvisible();
}

////////////////////////////////////////////////////////////
// Function: CopySpritesIntoOAM
// Copies our version of Sprite Attributes into Gameboys
// OAM memory location.
// this should be called, anytime any sprite changes.
////////////////////////////////////////////////////////////
void CopySpritesIntoOAM()
{
    DMAFastCopy((void*)g_spriteAttributes, (void*)SpriteMem, 512, DMA_16NOW);
}

////////////////////////////////////////////////////////////
// sprite Handler Creation
////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////
// Function: newSpriteHandler
// Gives pointer to brand spanking new spritehandler
// that the user can manipulate
// Note: Sets unique ID.
// Return: SpriteHandler pointer. Null if Space if filled
////////////////////////////////////////////////////////////
SpriteHandler * newSpriteHandler()
{
	// get smallest available unique ID
	int id = getNextSpriteHandlerID();
	
	// If we ran out of room, return NULL
	if ( id == -1 )
	{
		return NULL;
	}
	
	// Clear out the SpriteHandler, just in case it is not clean already
	cleanSpriteHandler( id );
	
	// TODO: Change this operation to be more like g_spriteHandlers[ id ] = { 0, 0, 1, ... } as it is MUCH FASTER
	//		need to put in stone all sprite handler fields first.
	
	// Set initial values
	g_spriteHandlers[ id ].alive				= TRUE;			// Make this sprite alive
	g_spriteHandlers[ id ].id 					= id;			// set id, this should be both the sprite attribute index and the index for this
	// g_spriteHandlers[ id ].enabled				= TRUE;		
	
	g_spriteHandlers[ id ].x 					= 0;			// position
	g_spriteHandlers[ id ].y 					= 0;			// position
    g_spriteHandlers[ id ].size 				= SD_8x8;		// default size
    g_spriteHandlers[ id ].flip 				= FLIP_NONE;	// flip?
    g_spriteHandlers[ id ].priority 			= 0;			// Draw priority
    g_spriteHandlers[ id ]._imageIndex 			= 0;			// image index
    g_spriteHandlers[ id ].currentAnimation 	= 0;			// the current animation index 
	
    g_spriteHandlers[ id ]._currentFrame 		= 0;			// current frame
    g_spriteHandlers[ id ]._currentUpdate 		= 0;			// current update counter
	g_spriteHandlers[ id ].animationComplete 	= FALSE;
    
    g_spriteHandlers[ id ].scale 				= 1 << 8;		// scale is set to 1
    g_spriteHandlers[ id ].angle 				= 0;

    g_spriteHandlers[ id ].width 				= 0;
    g_spriteHandlers[ id ].height 				= 0;
	
	g_spriteHandlers[ id ].userData 			= NULL;			// User data is null
	
	// Clear out Animation Info ( should be zerod out anyways ... whatever )
	memset( g_spriteHandlers[ id ].animations, 0, sizeof( AnimationInfo ) * MAX_ANIMATIONS );
	
	// Return pointer to sprite handler
	return &g_spriteHandlers[ id ];
}

////////////////////////////////////////////////////////////
// Sprite Handler "Methods"
////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////
// Function: updateSpriteAttributes
// Updates the Sprite Attributes for this SpriteHandler
// Note: Does not update into OAM Memory, only our copy.
////////////////////////////////////////////////////////////
void updateSpriteAttributes( SpriteHandler const * sprite_handler )
{
	// get the index in the 
	int sprite_index = sprite_handler->id;

	short shape = SQUARE;
	short size = SIZE_8;
	
	unsigned char x, y;
	
	int affineMatrixIndex = GetSpriteAffineMatrixIndex(sprite_handler);
	int canRotate = ROTATION_FLAG;
	
	if (!affineMatrixIndex) {
	    canRotate = 0;
    }
	
	// If the sprite handler is alive and visible, set the x vals to the ones given
	if ( sprite_handler->alive  )
	{
		x = sprite_handler->x;
		y = sprite_handler->y;
	}
	else
	{
		x = SCREEN_WIDTH;
		y = SCREEN_HEIGHT;
	}
	
    // Set the Sprite Data
	// Based off the sprite attributes 0 and 1	
	// ->([xy]); //
	// ->$1
    switch ( sprite_handler->size )
    {
        case SD_8x8:
			shape = SQUARE;
			size = SIZE_8;
            break;
        case SD_8x16:
			shape = TALL;
			size = SIZE_8;
            break;
        case SD_8x32:
			shape = TALL;
			size = SIZE_16;
            break;
        case SD_16x8:
			shape = WIDE;
			size = SIZE_8;
            break;
        case SD_16x16:
			shape = SQUARE;
			size = SIZE_16;
            break;
        case SD_16x32:
			shape = TALL;
			size = SIZE_32;
            break;
        case SD_32x8:
			shape = WIDE;
			size = SIZE_16;
            break;
        case SD_32x16:
			shape = WIDE;
			size = SIZE_32;	
            break;
        case SD_32x32:
			shape = SQUARE;
			size = SIZE_32;				
            break;
        case SD_32x64:
			shape = TALL;
			size = SIZE_64;
            break;
        case SD_64x32:
			shape = WIDE;
			size = SIZE_64;
            break;
        case SD_64x64:
			shape = SQUARE;
			size = SIZE_64;
            break;
        default:
            break;
    }

	//attribute0: color mode, shape and y pos
	g_spriteAttributes[sprite_index].attribute0 = 
		COLOR_256 | 
		shape | 
		y |
        canRotate;

    //attribute1: size and x pos
	g_spriteAttributes[sprite_index].attribute1 =
		size |
		x |
		sprite_handler->flip |
        ROTDATA(affineMatrixIndex);
	
    //attribute2: Image location
    g_spriteAttributes[sprite_index].attribute2 = sprite_handler->_imageIndex;
}

////////////////////////////////////////////////////////////
// Function: AddSpriteAnimation
// Adds an animation to the given sprite
////////////////////////////////////////////////////////////
void AddSpriteAnimation(SpriteHandler * sprite, int const anim_index, AnimationInfo const anim)
{
    sprite->animations[ anim_index ] = anim;
}

////////////////////////////////////////////////////////////
// Function: SetSpriteAnimation
// Sets the current running animation of a sprite
////////////////////////////////////////////////////////////
void SetSpriteAnimation(SpriteHandler * sprite_handler, int animation_index)
{
    sprite_handler->currentAnimation = animation_index;
    sprite_handler->_imageIndex = sprite_handler->animations[ animation_index ].frames[ 0 ];
    sprite_handler->_currentFrame = 0;
    sprite_handler->_currentUpdate = 0;
}

////////////////////////////////////////////////////////////
// Function: UpdateSpriteAnimation
// Updates the Sprite's Animation
// TODO: FIX THIS PIECE OF SHIT. Take out the copy at the
// 		begining and make it all pointers, that's right
//		you heard me ALL POINTERS. Srsly, shouldn't cause
//		problems.
////////////////////////////////////////////////////////////
void UpdateSpriteAnimation(SpriteHandler * sprite)
{
    // make a local copy and use that, then copy the local copy over the pointer's data
    SpriteHandler sprite_handler = *sprite;
    
    // Increment number of updates that have been called for this animation
    ++sprite_handler._currentUpdate;
    
    // If we've reached the number of updates required to go onto the next
    // frame, then do so
    if ( sprite_handler._currentUpdate >= sprite_handler.animations[ sprite_handler.currentAnimation ].updatesPerFrame )
    {
        // go to next frame
        ++sprite_handler._currentFrame;
        
        // If the current frame is bigger than or equal to the number of frames, see if we are looping
        // if so, go back to the first frame, else stay where we are
        if ( sprite_handler._currentFrame >= sprite_handler.animations[ sprite_handler.currentAnimation ].numFrames )
        {
            if ( sprite_handler.animations[ sprite_handler.currentAnimation ].looping )
			{
                sprite_handler._currentFrame = 0;
			}
            else
			{
                sprite_handler._currentFrame = sprite_handler.animations[ sprite_handler.currentAnimation ].numFrames - 1;
				sprite_handler.animationComplete = TRUE;
			}
        }
        
        // Set the Image Index to the value at the current frame
        sprite_handler._imageIndex = sprite_handler.animations[ sprite_handler.currentAnimation ].frames[ sprite_handler._currentFrame ];
        
        // Reset counter
        sprite_handler._currentUpdate = 0;
    }
    
    // Set the value
    *sprite = sprite_handler;
}

////////////////////////////////////////////////////////////
// Function: GetSpriteWidth
// Helper Function that returns the numerical value of the sprite's width
////////////////////////////////////////////////////////////
int GetSpriteWidth(SpriteHandler const * sprite)
{
    switch ( sprite->size )
    {
        case SD_8x8:
            return 8;
            break;
        case SD_8x16:
            return 8;
            break;
        case SD_8x32:
            return 8;
            break;
        case SD_16x8:
            return 16;
            break;
        case SD_16x16:
            return 16;
            break;
        case SD_16x32:
            return 16;
            break;
        case SD_32x8:
            return 32;
            break;
        case SD_32x16:
            return 32;
            break;
        case SD_32x32:
            return 32;
            break;
        case SD_32x64:
            return 32;
            break;
        case SD_64x32:
            return 64;
            break;
        case SD_64x64:
            return 64;
            break;
        default:
            break;
    }
    
    return 0;
}

////////////////////////////////////////////////////////////
// Function: GetSpriteHeight
// Helper Function that returns the numerical value of the sprite's height
////////////////////////////////////////////////////////////
int GetSpriteHeight(SpriteHandler const * sprite)
{
    switch (sprite->size)
    {
        case SD_8x8:
            return 8;
            break;
        case SD_8x16:
            return 16;
            break;
        case SD_8x32:
            return 32;
            break;
        case SD_16x8:
            return 8;
            break;
        case SD_16x16:
            return 16;
            break;
        case SD_16x32:
            return 32;
            break;
        case SD_32x8:
            return 8;
            break;
        case SD_32x16:
            return 16;
            break;
        case SD_32x32:
            return 32;
            break;
        case SD_32x64:
            return 64;
            break;
        case SD_64x32:
            return 32;
            break;
        case SD_64x64:
            return 64;
            break;
        default:
            break;
    }

    return 0;
}

////////////////////////////////////////////////////////////
// Function: GetSpriteHeight
// Helper Function that returns the numerical value of the sprite's height
////////////////////////////////////////////////////////////
int GetSpriteAffineMatrixIndex(SpriteHandler const * sprite)
{
    // implemented w/ a switch statement to avoid costly division
    switch (sprite->angle) {
        case 0: return 0; break;
        case 15: return 1; break;
        case 30: return 2; break;
        case 45: return 3; break;
        case 60: return 4; break;
        case 75: return 5; break;
        case 90: return 6; break;
        case 105: return 7; break;
        case 120: return 8; break;
        case 135: return 9; break;
        case 150: return 10; break;
        case 165: return 11; break;
        case 180: return 12; break;
        case 195: return 13; break;
        case 210: return 14; break;
        case 225: return 15; break;
        case 240: return 16; break;
        case 255: return 17; break;
        case 270: return 18; break;
        case 285: return 19; break;
        case 300: return 20; break;
        case 315: return 21; break;
        case 330: return 22; break;
        case 345: return 23; break;
    }

    return 0;
}

////////////////////////////////////////////////////////////
// INTERNALLY USED FUNCTIONS. DON'T USE outside of this file
////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////
// Function: getNextSpriteHandlerID
// Returns the smallest available entity id
////////////////////////////////////////////////////////////
int getNextSpriteHandlerID()
{
    int id;
    for ( id = 0 ; id < MAX_SPRITE_HANDLERS ; ++id )
    {
        // if we find a dead sprite handler
        if ( ! g_spriteHandlers[ id ].alive )
        {
            // return that id
            return id;
        }
    }
    
    return -1;
}

////////////////////////////////////////////////////////////
// Function: cleanSpriteHandler
// Zero outs all the data in a sprite handler.
////////////////////////////////////////////////////////////
void cleanSpriteHandler( int const id )
{
	// zero out the pertaining sprite attribute structure
	memset ( &g_spriteAttributes[ id ], 0, sizeof( SpriteAttributes ) );
	
	// One of these two methods cause the game to crash
	
	SpriteHandler * sprite_handler = &g_spriteHandlers[ id ];
	
	// free user data
	SAFE_FREE ( sprite_handler->userData );
	
	// Zero set animation
	memset( g_spriteHandlers[ id ].animations, 0, sizeof( AnimationInfo ) * MAX_ANIMATIONS );
}

/////////////////////////////////////////////////////////////
// Function: RotateSprite
// Rotates and scales a hardware sprite
/////////////////////////////////////////////////////////////
void RotateSprite(int rotDataIndex, int angle, signed int xscale, signed int yscale)
{
    signed int pa,pb,pc,pd;

    // use the pre-calculated fixed-point arrays
    pa = ((xscale) * COS[angle]) >> 8;
    pb = ((yscale) * SIN[angle]) >> 8;
    pc = ((xscale) * -SIN[angle]) >> 8;
    pd = ((yscale) * COS[angle]) >> 8;

    // update the rotation array entry
    rotData[rotDataIndex].pa = pa;
    rotData[rotDataIndex].pb = pb;
    rotData[rotDataIndex].pc = pc;
    rotData[rotDataIndex].pd = pd;
}

#endif

